Laravel and Vue.js
和訳しながらメモしていく
本のリポジトリ
1.Introduction
公式ドキュメント
多少PHPとJSの基礎知識は必要だよということが書かれている
2. Vue.js Basics
code:vue.js
<div id="app">
{{ message }}
</div>
...
<script src="vue.js/..."> // パッケージ
<script>
const app = new Vue({
el:'#app',
data: {
message: 'hello'
}
});
el
本文中のdivタグと一致させ、vueが動作する場所を決定する
data
コンポーネント中で使用するオブジェクトの定義をする。
3. Conditionals and Loops
条件分岐とループの概念。
code:vue.js
<div id="app">
<p v-if="visible">see this </p>
</div>
data側でvisible: trueと定義しておくことで、その値に応じて値が消える。
display:noneではなく、DOMから完全に消える。displayを操作するものは別にある。
code:vue.js
<li v-for="animal in animals">
{{ animal }}
</li>
これもdata側でanimals配列を用意しておくことで、指定した変数名で回すことができる。
animal in animals: animals配列をanimalとしてforeachの挙動で回すイメージ。
data: { animals: ['Dog', 'Cat', 'Bird']}
4.Vue.js Forms
v-model
指定した名前で、script側で定義しているdata()側にバインドさせる
v-onなど
ボタンに付与して、動作に応じてメソッドを呼び出せる
code:vue.js
<button v-on:click="sayHi">sayHiメソッドを呼ぶ</button>
...
<script>
const app = new Vue({
data: {
name: ''
},
methods: {
sayHi() { alert('Hi there, ' + this.name)}
}
これは<button @click="sayHi">と置き換えることもできる
enterキーなどを使いたいなら、テキストボックス側に指定の記述をすることでメソッドを呼べる
code:html
<p>
名前入力:
<input type="text" v-model="name" @keyup.enter="sayHi">
</p>
<button @click="sayHi">メソッド</button>
5.components
デフォルトの記述方式
code:js
<div id="app>
<hello-world></hello-world>
</div>
<script>
Vue.component('hello-world', {
template: '<div>Hello!</div>'
});
const app = new Vue({
el: '#app"
});
</script>
この辺がlaravelはうまいこと自動化されているが、vueだけで実装するなら上記の感じになる
この章のjsを追いかけてみる
code:LoopTest.vue
<template>
<div>
<ul>
<li v-for="task in tasks">{{ task }}</li>
</ul>
<input type="text" v-model="newTask" @keyup.enter="addTask">
<button @click="addTask">Add Task</button>
</div>
</template>
<script>
export default {
methods: {
addTask() {
this.tasks.push(this.newTask);
this.newTask = '';
}
}
};
</script>
code:html
<div id="loop_test">
<h4>Team Tasks</h4>
<h5>A task</h5>
<loop-test></loop-test>
<h5>B task</h5>
<loop-test></loop-test>
</div>
inputで書いたテキストをaddTask()関数を経由して追加させられる。
liは関数が走るたび更新される。
6.HomeStead
7. Laravel Setup
HomeStead
Laravelで作成できる仮想サーバーのこと
valet
同じくlaravelを開発する際に立ち上げることができる仮想サーバー
mac向らしい。
環境構築用のチャプターである
8.Purchases Component
9.Purchases Table
Laravelプロジェクトでvueを使う時の基礎
app.jsへの記述
code:app.js
Vue.component('purchases-component', require('./components/PurchasesComponent.vue').default);
これだけで良いかも。
第一引数はhtml要素の名前
requireで定義するのは呼ぶコンポーネントのファイル。
? 既存の学習ページの警告を消してみる
app.js?id=8281c32e54cc3d596623:44541 [Vue warn]: Cannot find element: #loop_testとかの部分。
mounted()
ページが読み込まれた時点で実行する処理のこと
この中にメソッドを書いていた場合は、DOMが成立した時点でそのメソッドを呼ぶという挙動になる
axios.get()
ajaxを使うためのライブラリ
ルート指定
study/techbook/vue/chapter8_purchasesとした場合
→現時点でのURLに+して、上のURLが参照される
/study/techbook/vue/chapter8_purchases
ドメイン + 指定のパスとして参照される(基本こっち)
読み込み中の画面を出す処理の理屈がわかったかも
v-ifで読み込む要素がまだ取得できていない場合はぐるぐるするgifを用意しておく
準備できた(axios.getなどで読み込めた = 変数に値が入ったら)、v-ifで切り替わるみたいなイメージ
10. Databse Setup
まあpurchasesテーブルを実際に作ってみようか
後で削除すれば良い。
$ php artisan make:model Purchase -m
外部キー制約など
code:php
$table->integer('user_id')->unsigned(); // unsigned: 符号無し
// purchasesテーブルのuser_idを、usersテーブルのidに紐付けることになる
// ("user_id" references "id" on "users" table.)
$table->foreign('user_id')->references('id')->on('users');
マイグレーションエラーになった
code:sh
Illuminate\Database\QueryException : SQLSTATEHY000: General error: 3780 Referencing column 'user_id' and referenced column 'id' in foreign key constraint 'purchases_user_id_foreign' are incompatible. (SQL: alter table purchases add constraint purchases_user_id_foreign foreign key (user_id) references users (id)) users.idがbigintegerで作成されたものだったのでそちらにuser_idの型も合わせた。
$table->bigInteger('user_id')->unsigned();
これで通った
ordeyByの呼び出しについて
code:php
// エラーになる
//BadMethodCallException Method Illuminate\Database\Eloquent\Collection::orderBy does not exist.
$purchases = Auth::user()->purchases->orderBy('date', 'desc')->get();
// ()を付属するとデータベースクエリビルだのメソッドが使える。
$purchases_t = Auth::user()->purchases()->orderBy('date', 'desc')->get();
11. Create Form
モーダルでDB登録フォームを作る
結構がっつり実装したので、書籍に書いてあるものを流れ通りに追っていく
モーダルを作成
PurchaseComponentに作成。
コンポーネントは1つのHTML要素しか持つことができないので、divの内部に記述していく
templateで実装した要素について
modal fade
背景が暗くなってフェードインさせるエフェクトにする
tabindex="-1"
従来tabキーを押すと画面内の別の要素に移動するが、指定することで(ざっくりだが)別枠として扱われる
モーダルに付与させると、モーダルの背後にあるコンテンツを操作不能にすることができる
UXが上がる
role="dialog"
tabindexと組み合わせて使用する。tabキーで別の要素にフォーカスされないようにする
data-dismissあたり
bootstrap側で操作するために必要な設定。上のdocsを見ると良い(基本モーダルを閉じるためのもの)
v-if="createForm.errors.length > 0"
data()で用意したcreateForm変数のerror配列に何かしら追加された場合に要素を出す。
form-horizontal
フォームの要素を1列ずつ並べて出す。レイアウト用。
Dateの入力フォーム
これだけid="create-purchase-date"が付与されている理由
モーダルを開いた時に、Dateに入力フォーカスが設定されるようにするため。
code:js
$('#modal-create-purchase').on('shown.bs.modal', () => {
$('#create-purchase-date').focus();
});
v-model="createForm.date"
指定した名前で、script側で定義しているdata()側にバインドさせる
ここで入力したものをcreateForm.dateに入れるということになる
jsで実装した要素について
showCreatePurchaseForm()
指定のモーダルを開く。
store()
persistPurchaseメソッドに各種引数を渡しているだけ。
この中では特に何かしているわけではない
persistPurchase(method, uri, form, modal)
form.errors = [];
このメソッドが実行されるたび、過去のエラーメッセージをリセットする役割
axios[method](uri, form)
Axioosライブラリを使用してHTTPリクエストを送信している
今回HTTP methodとしてpostが指定されているので、axios.post(uri, form)が使われている
.then(response => {
正常に成功した時の挙動を記載するパーツ。
this.getPurchases();
データを保存した後にもう一度APIからデータを呼び出している。
これで表示されるデータが保存後の最新状態になる
form.date = '';など
フォームフィールドをクリアし、再度入力しやすくする
$(modal).modal('hide');
モーダルを閉じる
.catch(error => {
リクエストが失敗した時の挙動。
エラーレスポンスデータがオブジェクトである場合
form.errors = _.flatten(_.toArray(error.response.data));
配列にうまいこと分けている処理。
それ以外の場合は汎用メッセージを出す。
12. Edit Form
編集画面を作成する
編集を表示させるスペースの作成
code:html
<td style="vertical-align: middle;">
<a class="action-link" @click="edit(purchase)">Edit</a>
</td>
v-forの中で回しているので、その中のpurchaseモデルが使える
クリックするとeditメソッドへ飛ばす。
モーダルについて
code:html
<input id="edit-purchase-date" type="text" class="form-control" @keyup.enter="update" v-model="editForm.date">
編集ボタンをクリックする前の値が格納されるが、これは
editForm.dateの参照
data()側で定義したもの。ただし現状はdate: ''としている
編集をクリックするとedit(purchase)が実行される
ここでthis.editForm.date = purchase.date;と設定しているから。
update()メソッド
code:js
update() {
this.persistPurchase(
'put', '/study/techbook/vue/chapter8_purchases/' + this.editForm.id,
this.editForm, '#modal-edit-purchase'
)
},
persistPurchase(method, uri, form, modal) { ... }
put
リソースの更新を明示するHTTPメソッド。
uri
新しくリソースを更新するためのパスをlaravel側のコントローラで定義してそちらに飛ばした。
form
どのフォームから来たのかの指定。
modal
HTMLのID。$(modal).modal('hide');する時に使う。
persistPurchase()は、axios[method](uri, form)が基本の処理
put/get/postなどmethodも指定できるので汎用性が高い。
13.Deleting Purchases
削除機能を作る
エラーに遭遇
code:txt
Error in v-on handler: "ReferenceError: log is not defined
console.logがconsole,logになってた...
エラーその2
code:txt
Vue warn: Error in v-on handler: "ReferenceError: purchase is not defined" code:js
destroy() {
axios.delete('/study/techbook/vue/chapter8_purchases/' + purchase.id)
.then(response => {
this.getPurchases();
});
},
destroy(purchase)として渡さないとダメ...
サーバーエラー
code:console.log
app.js?id=34d62ba663f0054a6f00:297
laravel側
code:txt
Call to undefined method App\User::purchase()
/var/www/laravel_kirthread/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php#50
BadMethodCallException
->purchase()じゃなくて->purchases()だっただけ
機能作成までのフロー
動作を実装させるためのボタンをviewに用意する
今回はaタグで出した項目。そこに@clickで動作するメソッドを仕込む
削除確認させたいならconfirm(purchase.id)など。
メソッドの調整をする
確認画面に出したいのであれば、ここに情報を記入する
メソッドの引数で渡した情報などを画面に仕込む。
code:html
<!-- こんな感じで。 -->
<div class="modal-body">
<p>purchase id: '{{ this.deleteId }}' will be deleted.</p>
</div>
data()で定義しておき、そちらに値を渡す感じで。
code:js
export default {
data() {
deleteId: ''
},
methods: {
function confirm(purchaseId) {
this.deleteId = purchaseId;
}
}
モーダル内のボタンで本命の処理を実行させる
aタグ用意してそこに@click=destroyみたいな感じ。
事前処理でdata()で定義した変数に値を入れているならば、そちらを使えば良いので引数は必要ない
code:js
destroy() {
axios.delete('/study/techbook/vue/chapter8_purchases/' + this.deleteId)
.then(response => {
this.getPurchases();
});
// 終わった後、元の画面に戻す処理
$('#modal-confirm-delete').modal('hide');
},
なるほど
14 Paging
外部モジュールを使う
バージョンが古いからきついかもな〜
code:sh
npm install laravel-vue-pagination
added 16 packages, removed 2 packages, changed 4 packages, and audited 1170 packages in 8s
22 packages are looking for funding
run npm fund for details
81 vulnerabilities (2 low, 47 moderate, 32 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
Run npm audit for details.
npm audit fixで依存関係を軽く治す
バージョンが古いから今回はこのまま行く
? vueを使うならlaravelのバージョンと一緒にverも併せてあげるべきかも.
まあこれはいいか(モジュール特有の操作っぽいし)